home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / go / comp / wally.sh < prev    next >
Encoding:
Linux/UNIX/POSIX Shell Script  |  1993-06-20  |  57.6 KB  |  2,157 lines

  1. #! /bin/sh
  2. # This is a shell archive, meaning:
  3. # 1. Remove everything above the #! /bin/sh line.
  4. # 2. Save the resulting text in a file.
  5. # 3. Execute the file with /bin/sh (not csh) to create:
  6. #    README
  7. #    wally.c
  8. # This archive created: Sat Jan 18 17:51:52 1992
  9. export PATH; PATH=/bin:/usr/bin:$PATH
  10. if test -f 'README'
  11. then
  12.     echo shar: "will not over-write existing file 'README'"
  13. else
  14. cat << \SHAR_EOF > 'README'
  15. From: kstock@isfrance.encore.fr (Kevin Stock)
  16. Subject: Adding MGT output to WALLY
  17.  
  18. It turned out that it was even easier than I thought to get
  19. Wally to produce output files that MGT can use. The changes
  20. are attached below in diff -c format for patch. If you don't
  21. have the patch program, I can send you a modified source.
  22.  
  23. To use the new code, you have to compile Wally with -DADDED.
  24. (If you have xtx, I've added an xtx line which will do this
  25. automatically.) The additions are:
  26.  
  27.   Three new options:
  28.  
  29.   -d  turns on debugging output
  30.   -mgt  writes the output record in a form suitable for mgt
  31.   -cat  writes the output record in a form suitable for wally <file
  32.  
  33.   The game score is printed even in the case of a resignation.
  34.  
  35. Feel free to add this to your archives and/or post it to
  36. rec.games.go (I can't post anything at present).
  37.  
  38.   ,---------------.
  39. ,-+-------------. |    Kevin Stock
  40. | | E N C O R E | |
  41. | `-------------+-'    kstock@gouldfr.encore.fr
  42. `---------------'      kstock@gouldfr.UUCP
  43.  
  44.  
  45.  
  46. OK, so mgt only uses a..s in its input file! Boy, is life complicated!
  47.  
  48. At the end of this message is a supplemental patch, which does the
  49. following:
  50.  
  51.     1)    uses a..s in the input files, instead of a..hj..t
  52.     2)    adds a comment for each move
  53.     3)    creates a new node for a pass, so the comments
  54.         don't run into each other and get lost
  55.     4)    uses Size instead of SiZe.
  56.         This is probably wrong, but it's convenient.
  57.     5)    introduces a PATCHLEVEL (== 2)
  58.  
  59. I'll send you another mail which is a single patch file to apply both
  60. patches, which would be more suitable for posting (if you haven't put
  61. the first one out yet).
  62.  
  63. Whew.
  64.     Kevin
  65.  
  66. SHAR_EOF
  67. fi
  68. if test -f 'wally.c'
  69. then
  70.     echo shar: "will not over-write existing file 'wally.c'"
  71. else
  72. cat << \SHAR_EOF > 'wally.c'
  73. /*  wally.c
  74. From: newman@tcgould.TN.CORNELL.EDU (Bill Newman)
  75. Subject: another simple-minded PD go-playing program
  76.  
  77. Before gnu-go was announced, I used the ideas in the BYTE article by J.K.
  78. Millen (April 1981) to make a go-playing program ("wally") of my own.
  79. Wally's only advantage over gnugo is that it plays better than the
  80. early gnugo versions that I saw (pulling ahead even before gnugo made its
  81. random self-destructive moves in the endgame).
  82. Wally uses explicit array addressing instead of pointer
  83. arithmetic, so it is slower than it should be, but otherwise I'm
  84. not too embarrassed by the details of the code.  (though constructive
  85. criticism is always appreciated)
  86.  
  87. The program is documented only by comments inside; the only features which may
  88. not be obvious are command-line options to create a game record,
  89. and to play on a range of board sizes, with or without handicap stones.
  90.  
  91. As noted in the comments, the program is copyrighted but freely available
  92. for not-for-profit use, such as anyone can find for it.
  93. The program is unlikely to hold the interest of a human opponent very long,
  94. especially since it plays an obnoxious endgame, singlemindedly throwing in
  95. to the enemy's territory whenever it sees the opportunity to keep the
  96. opponent from making the maximum number of eyes.  However, it
  97. might be of interest
  98. to programmers wondering how far you can get with a simple pattern-matching
  99. program, or just looking for more patterns for their tables; most of the
  100. patterns in the program's table (all those not in Millen's article) are 
  101. original with me; I started with Millen's shape table,
  102. then spent several hours playing against the program (mostly on a 9x9 
  103. board with 4-stone handicap) and changing the table to keep the program
  104. from doing unnecessarily stupid things.  
  105.  
  106. The source code to the program follows the dotted line, and
  107. continues to the end of the file.  The program compiles and
  108. runs with cc under SunOS 4.0.3 and and with Mark Williams C 3.0 on
  109. an Atari 520 ST.
  110.  
  111.   Bill Newman
  112.   newman@tcgould.tn.cornell.edu
  113.  
  114. ------------------------------------------------------------------------  
  115. */
  116.  
  117. /*
  118. wally.c, a go playing program
  119. Copyright (c) 1988 by William H. Newman and distributed as shareware:
  120.  permission is granted for all non-profit use of the program as
  121.  long as this notice is included.
  122. Send comments to box 172 Cornell U, Ithaca NY 14850, or e-write
  123.  to newman@batcomputer.tn.cornell.edu.  
  124. This program was inspired by ideas published by Jonathan K. Millen in BYTE,
  125.  April 1981.  Because an Atari ST is somewhat more powerful than a KIM-1,
  126.  I have been able to make the program somewhat more sophisticated.
  127.  However, it still plays very naive go.  (30 kyu?)
  128.  
  129. Notable flaws:
  130.   no lookahead
  131.   no knowledge of live or dead shape
  132.   takes advantage of a series of opponent's passes @ the start of the game
  133.     rather poorly; this points up flaws in the shape table
  134.   no rules to stop the program from making obnoxious but pointless moves
  135.     in the endgame; it ought not to once it has passed once.  Maybe turn
  136.     off pattern matching completely after the program's first pass move.
  137.  
  138. #ifdef  ADDED
  139.   Three new options:
  140.  
  141.   -d  turns on debugging output
  142.   -mgt  writes the output record in a form suitable for mgt
  143.   -cat  writes the output record in a form suitable for cat ... | wally
  144.  
  145.   The game score is printed even in the case of a resignation.
  146.  
  147.   <-xtx-*>    cc -o wally -O -DADDED wally.c
  148.  
  149.   Added by Kevin Stock, kstock@encore.fr, 12th July 1990
  150. #endif
  151.  
  152. */
  153.  
  154.  
  155. #include <stdio.h>
  156. /* #include <string.h>  */
  157. #include <strings.h>
  158.  
  159. #ifdef  ADDED
  160. # define  PATCHLEVEL    2
  161.  
  162. # define  WALLY_OUTPUT  0
  163. # define  MGT_OUTPUT    1
  164. # define  CAT_OUTPUT    2
  165.  
  166. # define  M_LETTER(x)    \
  167.     ((x < 8) ? lettercol(x) : ((x == 8) ? 'i' : lettercol(x - 1)))
  168.  
  169.   int outputmode = WALLY_OUTPUT;
  170. #endif
  171.  
  172. #define ASSERT 1    /*flag for whether assert() macros should be */
  173.             /* expanded*/
  174.  
  175. #define BIGU 10000    /*a number higher than any meaningful "urgency" */
  176.             /* or move importance*/
  177.  
  178. #define RESIGN (-2)    /*codes for resigning */
  179. #define PASS (-1)    /* passing moves*/
  180. #define BOTHPASS (-3)    /*code for both sides passed, game is over*/
  181.  
  182. #define EDGE 23        /*max # intersections on the edge of a go board*/
  183. int edge= 9;        /*the number of intersections which we are using (a */
  184.             /* command line parameter)*/
  185.  
  186. #define NPLAYERS 2    /*# players (hence # copies to keep of score &c.)*/
  187.  
  188. int debugattack= 0;    /*flag for printing debugging messages in attack()*/
  189.  
  190. /*Return the absolute value of i.*/
  191. #define abs(i) ((i)>=0?(i):-(i))
  192.  
  193. /*Return TRUE if (x,y) corresponds to a point on the board.*/
  194. #define on1board(x) (0<=(x)&&(x)<edge)
  195. #define onboard(x,y) (on1board(x)&&on1board(y))
  196.  
  197. /*Return TRUE if (x,y) is on the edge of the board.*/
  198. #define onedge1(x) (0==(x)||edge-1==(x))
  199. #define onedge(x,y) (onedge1(x)||onedge1(y))
  200.  
  201. /*codes for players; and a code for something (e.g. a point on the board) */
  202. /* which belongs to neither*/
  203. #define BLACK 0
  204. #define WHITE 1
  205. #define EMPTY 2
  206. /*flags in shape table entries for types of points*/
  207. #define F_BLACK 1    /*the point has a black stone*/
  208. #define F_WHITE 2    /*the point has a white stone*/
  209. #define F_EMPTY 4    /*the point is empty*/
  210. #define F_OFF   8    /*the point is off the board*/
  211. int flookup[]=    /*sets of flags corresponding to codes*/
  212. { F_BLACK, F_WHITE, F_EMPTY };
  213.  
  214. int evenmode= 0;    /*Are we (against our better judgment) to play */
  215.             /* an even game?*/
  216.  
  217. /*Return TRUE if a move violates ko.*/
  218. #define ko(x,y) (thegame.kox==(x)&&thegame.koy==(y))
  219.  
  220. /*Return the code for the other player, who is the next to play.*/
  221. #define nextp(p) (BLACK==(p)?WHITE:WHITE==(p)?BLACK:\
  222.     panic("illegal input to nextp()"))
  223.  
  224. /*Return a letter corresponding to column x; 'i' is omitted from letter */
  225. /* sequence by tradition.*/
  226. #define lettercol(x) (                            \
  227.       (0<=(x)&&(x)<=7) ? 'a'+(x) : (7<(x)&&(x)<edge) ? 'a'+(x)+1 :    \
  228.       panic("illegal lettercol()") )
  229.  
  230. /*Convert any uppercase letter to lowercase.*/
  231. #define lowercase(c) ('A'<=(c)&&(c)<='Z'?(c)-'A'+'a':(c))
  232.  
  233. /*Return a string naming BLACK or WHITE.*/
  234. char whitename[]="white", blackname[]="black";
  235. #define pname(c) (BLACK==(c)?blackname:WHITE==(c)?whitename:\
  236.     (panic("illegal input to pname()"),""))
  237.  
  238. /*Return TRUE if a move would leave the group it creates or attaches to */
  239. /* in atari or dead.*/
  240. #define intoatari(x,y) (subj_lib(x,y)<=1)
  241.  
  242. /*a macro to abort the program if a test is not successful*/
  243. #if ASSERT
  244. #define assert(q) ((q)?1:(fprintf(stderr, \
  245. "\n?!panic--failed assert() @ %s %d.\n", \
  246.  __FILE__, __LINE__), fflush(stderr),exit(1)))
  247. #else
  248. #define    assert(q)
  249. #endif
  250.  
  251. /*ASCII character codes*/
  252. #define TAB 8
  253.  
  254.  
  255. /*name of and pointer to output file*/
  256. char *ofname;
  257. FILE *ofile= 0;
  258.  
  259. /*name program uses for itself*/
  260. char *progname= "Wally";
  261. char version[]= "2.1";
  262.  
  263. /*a struct for holding information on every square of the board*/
  264. typedef int board[EDGE][EDGE];
  265.  
  266. /*current position of stones on the board*/
  267. board theboard;
  268.  
  269. /*other information about the game*/
  270. struct thegame
  271. { int kox, koy;        /*coords of current ko, or negative for none*/
  272.   int pla;        /*code for next player to play*/
  273.   int tur;        /*the number of this move*/
  274.   int qpa;        /*flag for the last move was a pass, so that if this */
  275.             /* move is a pass, that's all folx*/
  276. } thegame;
  277.  
  278. typedef struct group
  279. { int    color,        /*the color of stones in this group*/
  280.     nliberties,    /*the number of liberties that this group has*/
  281.     nstones,    /*the number of stones in this group*/
  282.     x, y;        /*one point in this group*/
  283. } group;
  284. group groups[EDGE*EDGE]; /*(EDGE*EDGE is a lazy bound; the number of groups */
  285.             /* of groups must be less than number of points)*/
  286. int ngroups;
  287.  
  288. /*handicap stones for the 3 common board sizes*/
  289. int handi9[]= { 2, 2,    6, 2,    2, 6,    6, 6 } ;
  290. int handi13[]= { 2, 2,    2, 6,    2, 10,    
  291.          6, 2,    6, 6,    6, 10,
  292.         10, 2,    10, 6,     10, 10 } ;  
  293. #if 0
  294. int handi19[]= { 15, 3, 15, 6,    15, 9,    15, 12,    15, 15,
  295.          12, 3,                12, 15,
  296.          9,  3,        9, 9,        9, 15,
  297.          6, 3,                 6, 15,
  298.          3, 3,    3, 6,    3, 9,    3, 12,    3, 15 } ;
  299. #else
  300. int handi19[]= { 15, 3,     15, 9,        15, 15,
  301.          9,  3,        9, 9,        9, 15,
  302.          3, 3,        3, 9,        3, 15 } ;
  303. #endif
  304.  
  305. int nhandicap[]=
  306. { 0, 0, 0, 0, 0,
  307.   0, 0, 0, 0, sizeof(handi9)/(2*sizeof(int)),
  308.   0, 0, 0, sizeof(handi13)/(2*sizeof(int)), 0,
  309.   0, 0, 0, 0, sizeof(handi19)/(2*sizeof(int))
  310. } ;
  311. int *handicap[]=
  312. { 0, 0, 0, 0, 0,
  313.   0, 0, 0, 0, handi9,
  314.   0, 0, 0, handi13, 0, 
  315.   0, 0, 0, 0, handi19
  316. } ;
  317.  
  318. /*a table of moves which seem to make "good shape" for the computer, */
  319. /* or which defend against a particularly common threat that the program */
  320. /* can't understand without lookahead, or which act as primitive joseki*/
  321. #define PATTERN 12345    /*This integer should appear at the start of each */
  322.         /* pattern.  If it doesn't, someone has made a typographical */
  323.         /* error.*/
  324. #define PATTEND 7171    /*This integer should appear at the end of the table.*/
  325. int patterns[]=
  326. {  PATTERN,    /*a code for the beginning of a pattern*/
  327.    4, 24,    /*Three points, basic urgency 24.  Urgency is highest */
  328.         /* for lower numbers.  Original values: */
  329.         /*   capturing an enemy group=16, */
  330.         /*   defending one of ours= 20, */
  331.         /*   atariing an enemy group= 32 */
  332.   -1, 0, F_BLACK|F_OFF, /*Recognize the pattern by black stone at (x-1, y+0) */
  333.         /* or that point off the board, */
  334.    1, 0, F_BLACK,  /* a black stone at (x+1, y+0), and */
  335.    0, -1, F_WHITE, /* a white stone at (x+0, y-1), and */
  336.    0, 1, F_EMPTY|F_WHITE, /* a white stone or space at (x, y+1), */
  337.     /* that is: */    /*   ~   */
  338.             /* ~ $ # */
  339.             /*   O   */
  340.  
  341.   PATTERN, 3, 22,    /* # $   */
  342.   -1, 0, F_BLACK,    /*   O # */
  343.    1, -1, F_BLACK,
  344.    0, -1, F_WHITE,
  345.  
  346.   PATTERN, 5, 26,    /* # O # */
  347.   -1, 1, F_BLACK|F_OFF,    /*   $ . */
  348.    1, 1, F_BLACK,    /*       */
  349.    0, 1, F_WHITE,    /*   ~   */
  350.    1, 0, F_EMPTY,
  351.    0, -3, F_EMPTY|F_WHITE,    /*This so that we don't get trapped in */
  352.             /* an extremely common pattern against the edge */
  353.             /* of the board, or in a shicho.*/
  354.  
  355.   PATTERN, 4, 26,    /* # O # */
  356.   -1, 1, F_BLACK|F_OFF,    /*   $ # */
  357.   1, 1, F_BLACK,
  358.   1, 0, F_BLACK,
  359.   0, 1, F_WHITE,
  360.  
  361.   PATTERN, 6, 24,    /*   ~     */
  362.   -1, 0, F_BLACK,    /* # $ . # */ 
  363.   0, -1, F_WHITE,    /*   O     */
  364.   1, 0,  F_EMPTY,
  365.   1, -1, F_EMPTY,
  366.   2, 0,  F_BLACK,
  367.   0, 1, F_EMPTY|F_WHITE,
  368.  
  369.   PATTERN, 5, 27,    /*   ~     */
  370.   -1, 0, F_BLACK,    /* # $ . ~ */ 
  371.   0, -1, F_WHITE,    /*   O     */
  372.   1, 0,  F_EMPTY,
  373.   2, 0,  F_OFF,
  374.   0, 1, F_EMPTY|F_WHITE,
  375.  
  376.   PATTERN, 5, 24,    /* # . $ . # */
  377.   -2, 0, F_BLACK,    /*     O     */
  378.   -1, 0, F_EMPTY,
  379.   0, -1, F_WHITE,
  380.   1,  0, F_EMPTY,
  381.   2,  0, F_BLACK,
  382.  
  383.   PATTERN, 5, 30,    /*  # . $ . ~  */
  384.   -2, 0, F_BLACK,    /*      O      */
  385.   -1, 0, F_EMPTY,
  386.   0, -1, F_WHITE,
  387.   1,  0, F_EMPTY,
  388.   2,  0, F_OFF,
  389.  
  390.   PATTERN, 7, 26,        /*    ~ .    */
  391.    -1, 0, F_BLACK,        /*  # $ # O  */
  392.    1, -1, F_WHITE,        /*    ~ O    */
  393.    1, 0, F_BLACK,
  394.    2, 0, F_WHITE,
  395.    1, 1, F_EMPTY,
  396.    0, 1, F_EMPTY|F_WHITE,
  397.    0, -1, F_EMPTY|F_WHITE,
  398.  
  399.   PATTERN, 8, 26,        /*  ~ # O  */
  400.   -1, -1, F_BLACK|F_EMPTY,    /*  # . $  */
  401.   -2, 0, F_BLACK,        /*  ~ ~ ~  */
  402.   -1, 0, F_EMPTY,
  403.   -1, 1, F_BLACK,
  404.    0, 1, F_WHITE,
  405.    0, -1, F_BLACK|F_EMPTY,
  406.   -2, -1, F_BLACK|F_EMPTY,  
  407.   -2, 1, F_BLACK|F_EMPTY,
  408.  
  409.   PATTERN, 4, 26,    /*   .   */
  410.   0, 2,  F_EMPTY,    /* #   # */
  411.   -1, 1, F_BLACK,    /*   $ O */
  412.   1, 1,  F_BLACK,
  413.   1, 0,  F_WHITE,
  414.  
  415.   PATTERN, 4, 24,    /*   .   */
  416.   0, 1, F_EMPTY,    /*   $   */
  417.   -1, -1, F_WHITE,    /* O # O */
  418.   0, -1, F_BLACK,
  419.   1, -1, F_WHITE,
  420.  
  421.   PATTERN, 4, 24,    /*   .   */
  422.   0, 1, F_EMPTY,    /*   $ O */
  423.   -1, -1, F_WHITE,    /* O #   */
  424.   0, -1, F_BLACK,
  425.   1, 0, F_WHITE,
  426.  
  427.   PATTERN, 4, 26,    /*   O   */
  428.   0, 1, F_EMPTY,    /* O . O */
  429.   -1, 1, F_WHITE,    /*   $   */
  430.   1, 1, F_WHITE,
  431.   0, 2, F_WHITE,
  432.  
  433.   PATTERN, 8, 24,      /*     O   */
  434.   -2, 0, F_EMPTY|F_BLACK, /* ~ $ # O */
  435.   0, -1, F_EMPTY,      /*   . . . */
  436.   1, -2, F_OFF,          /*     ~   */
  437.   1, -1, F_EMPTY,
  438.   1, 0, F_BLACK,
  439.   1, 1, F_WHITE,
  440.   2, -1, F_EMPTY,
  441.   1, 0, F_WHITE,
  442.  
  443.   PATTERN, 8, 28,    /* . # O   */
  444.   -1, 0, F_EMPTY,    /* . $ # O */
  445.   0, -1, F_EMPTY,    /*   . .   */
  446.   0, 1, F_BLACK,
  447.   1, 0, F_BLACK,
  448.   1, 1, F_WHITE,
  449.   2, 0, F_WHITE,
  450.   -1, 1, F_EMPTY,
  451.   1, -1, F_EMPTY,
  452.  
  453.   PATTERN, 8, 23,    /*   # #   */
  454.   0, 2, F_BLACK,    /*   .   # */
  455.   1, 2, F_BLACK,    /* ~ $ . # */
  456.   2, 0, F_BLACK,    /*   ~     */
  457.   2, 1, F_BLACK,
  458.   1, 0, F_EMPTY,
  459.   0, 1, F_EMPTY,
  460.   -1, 0, F_EMPTY|F_BLACK|F_WHITE,
  461.   0, -1, F_EMPTY|F_WHITE,
  462.  
  463.   PATTERN, 8, 24,    /*   O O   */
  464.   0, 2, F_WHITE,    /*   .   O */
  465.   1, 2, F_WHITE,    /* ~ $ . O */
  466.   2, 0, F_WHITE,    /*   ~     */
  467.   2, 1, F_WHITE,
  468.   1, 0, F_EMPTY,
  469.   0, 1, F_EMPTY,
  470.   -1, 0, F_EMPTY|F_WHITE|F_BLACK,
  471.   0, -1, F_EMPTY|F_BLACK,
  472.  
  473.   PATTERN, 8, 34,    /* ~ # # */
  474.   -1, 1, F_BLACK,    /* # . # */
  475.   -1, 0, F_BLACK,    /* # $   */
  476.   0, 2, F_BLACK,    /*   ~   */
  477.   0, 1, F_EMPTY,
  478.   1, 1, F_BLACK,
  479.   1, 2, F_BLACK,
  480.   -1, 2, F_BLACK|F_EMPTY,
  481.   0, -1, F_WHITE|F_EMPTY,
  482.  
  483.   PATTERN, 7, 34,        /* ~ # ~ */
  484.   -1, 1, F_BLACK,        /* # . # */
  485.   -1, 0, F_BLACK|F_EMPTY,    /* ~ $   */
  486.   -1, 2, F_BLACK|F_EMPTY,
  487.   0, 2, F_BLACK,
  488.   0, 1, F_EMPTY,
  489.   1, 1, F_BLACK,
  490.   1, 2, F_BLACK|F_EMPTY,
  491.  
  492.   PATTERN, 10, 27,    /*   . . .   */    /*(This is Wally's fuseki for */
  493.   -2, 0, F_BLACK,    /* # . $ . # */    /* a 9 x 9 board with 4 handicap */
  494.   2, 0, F_BLACK,    /*   . . .   */    /* stones.)*/
  495.   -1, 0, F_EMPTY,
  496.   1, 0, F_EMPTY,
  497.   -1, 1, F_EMPTY,
  498.   0, 1, F_EMPTY,
  499.   1, 1, F_EMPTY,
  500.   -1, -1, F_EMPTY,
  501.   0, -1, F_EMPTY,
  502.   1, -1, F_EMPTY,
  503.  
  504.   PATTERN, 6, 25,    /*     # . #   */
  505.   -1, 1, F_BLACK,    /*   ~ . $     */
  506.   -1, -1, F_BLACK,    /*     #       */
  507.   1, 1, F_BLACK,
  508.   0, 1, F_EMPTY,
  509.   -1, 0, F_EMPTY,
  510.   -2, 0, F_EMPTY|F_BLACK|F_OFF,
  511.  
  512.   PATTERN, 5, 35,    /*     O #   */
  513.   -1, 0, F_EMPTY,    /*   . $ ~   */
  514.   0, 1, F_WHITE,    /*     ~     */
  515.   1, 1, F_BLACK,
  516.   0, -1, F_OFF,
  517.   0, 1, F_BLACK|F_EMPTY,
  518.  
  519.   PATTERN,  5, 40,    /*   O #     */
  520.   -1, 0, F_EMPTY,    /*   . $ ~   */
  521.   -1, 1, F_WHITE,    /*     ~     */
  522.   0, 1, F_BLACK,
  523.   0, -1, F_OFF,
  524.   1, 0, F_WHITE|F_EMPTY,
  525.  
  526.   PATTERN, 6, 38,    /*   O . #   */
  527.   -1, 1, F_WHITE,    /*     $ .   */
  528.   1, 1, F_BLACK,    /*     .     */
  529.   0, 1, F_EMPTY,    /*     ~     */
  530.   1, 0, F_EMPTY,
  531.   0, -1, F_EMPTY,
  532.   0, -2, F_OFF|F_BLACK,
  533.  
  534.   PATTERN, 6, 38,    /*     . #   */
  535.   -1, 0, F_WHITE,    /*   O $ .   */
  536.   1, 1, F_BLACK,    /*     .     */
  537.   0, 1, F_EMPTY,    /*     ~     */
  538.   1, 0, F_EMPTY,
  539.   0, -1, F_EMPTY,
  540.   0, -2, F_OFF|F_BLACK,
  541.  
  542. /*
  543. some patterns for a 19 x 19 board, which is a little different from
  544. the high handicap 9 x 9 game this program originally played
  545. */
  546.  
  547.   PATTERN, 11, 29,      /*     O   */
  548.   -2, 0, F_EMPTY|F_BLACK, /* ~ $ # O */
  549.   0, -1, F_EMPTY,      /*   . . . */
  550.   1, -2, F_OFF,          /*   ~ ~ ~ */
  551.   1, -1, F_EMPTY,      /*     ~   */
  552.   1, 0, F_BLACK,
  553.   1, 1, F_WHITE,
  554.   2, -1, F_EMPTY,
  555.   -1, -2, F_EMPTY|F_OFF,
  556.   0, -2, F_EMPTY|F_OFF,
  557.   1, -2, F_EMPTY|F_OFF,
  558.   1, 0, F_WHITE,
  559.  
  560.   PATTERN, 12, 38,    /*     ~ #   */
  561.   -1, 0, F_WHITE,    /*   O $ ~ ~ */
  562.   1, 1, F_BLACK,    /*     ~ ~ ~ */
  563.   0, 1, F_EMPTY|F_BLACK,/*     ~ ~ ~ */
  564.   1, 0, F_EMPTY|F_WHITE,/*     ~     */
  565.   0, -3, F_OFF,
  566.   0, -1, F_EMPTY|F_BLACK,
  567.   0, 2,  F_EMPTY|F_BLACK|F_OFF,
  568.   1, -1, F_EMPTY|F_BLACK|F_OFF,
  569.   2, -1, F_EMPTY|F_BLACK|F_OFF,
  570.   0, -2, F_EMPTY|F_BLACK|F_OFF,
  571.   1, -2, F_EMPTY|F_BLACK|F_OFF,
  572.   2, -2, F_EMPTY|F_BLACK|F_OFF,
  573.  
  574.   PATTERN, 12, 38,    /*     # ~   */
  575.   -1, 0, F_WHITE,    /*   O $ ~ ~ */
  576.   0, 1, F_BLACK,    /*     ~ ~ ~ */
  577.   1, 1, F_EMPTY|F_BLACK,/*     ~ ~ ~ */
  578.   1, 0, F_EMPTY|F_WHITE,/*     ~     */
  579.   0, -3, F_OFF,
  580.   0, -1, F_EMPTY|F_BLACK,
  581.   0, 2,  F_EMPTY|F_BLACK|F_OFF,
  582.   1, -1, F_EMPTY|F_BLACK|F_OFF,
  583.   2, -1, F_EMPTY|F_BLACK|F_OFF,
  584.   0, -2, F_EMPTY|F_BLACK|F_OFF,
  585.   1, -2, F_EMPTY|F_BLACK|F_OFF,
  586.   2, -2, F_EMPTY|F_BLACK|F_OFF,
  587.  
  588. /*
  589. Let's not just pass when confronted by
  590. an empty 19 x 19 board.. hence the following patterns
  591. */
  592.  
  593.   PATTERN, 15, 25,    /*           ~     */
  594.   0, 1, F_EMPTY,    /*           ~ ~   */
  595.   0, 2, F_EMPTY,    /*     . . .       */
  596.   1, 0, F_EMPTY,    /*   . . . .        */
  597.   1, 1, F_EMPTY,    /*   . $ . .        */
  598.   1, 2, F_EMPTY,    /*     . .       */
  599.   2, 0, F_EMPTY,
  600.   2, 1, F_EMPTY,
  601.   2, 2, F_EMPTY,
  602.   4, 3, F_OFF,
  603.   3, 4, F_OFF,
  604.   -1, 0, F_EMPTY,
  605.   -1, 1, F_EMPTY,
  606.   0, -1, F_EMPTY,
  607.   1, -1, F_EMPTY,
  608.   3, 3, F_EMPTY|F_WHITE|F_BLACK,
  609.  
  610.   PATTERN, 10, 29,
  611.   -1, 0, F_EMPTY,    /*         ~     */
  612.   -1, 1, F_EMPTY,    /*         ~ ~   */
  613.   0, -1, F_EMPTY,    /*   . . .       */
  614.   1, -1, F_EMPTY,    /*   . $ .       */
  615.   0, 1, F_EMPTY,    /*     . .     */
  616.   1, 0, F_EMPTY,
  617.   1, 1, F_EMPTY,
  618.   2, 2, F_EMPTY|F_WHITE|F_BLACK,
  619.   3, 2, F_OFF,
  620.   2, 3, F_OFF,
  621.  
  622.   PATTERN, 17, 29,    /*     . . .          */
  623.   0, 1, F_EMPTY,    /*     . . .          */
  624.   0, -1, F_EMPTY,    /*   ~ . $ .   ~ ~    */
  625.   1, 0, F_EMPTY,    /*     . . .          */
  626.   -1, 0, F_EMPTY,    /*     . . .          */
  627.   1, 1, F_EMPTY,
  628.   1, -1, F_EMPTY,
  629.   -1, 1, F_EMPTY,
  630.   -1, -1, F_EMPTY,
  631.   -1, 2, F_EMPTY,
  632.   0, 2, F_EMPTY,
  633.   1, 2, F_EMPTY,
  634.   -1, -2, F_EMPTY,
  635.   0, -2, F_EMPTY,
  636.   1, -2, F_EMPTY,
  637.   3, 0, F_WHITE|F_BLACK|F_EMPTY,
  638.   4, 0, F_OFF|F_BLACK,
  639.   -2, 0, F_WHITE|F_EMPTY,
  640.   
  641.  
  642.   PATTERN, 12, 31,    /*     . . .     */
  643.   0, 1, F_EMPTY,    /*     . $ .     */
  644.   0, -1, F_EMPTY,    /*   ~ . . . ~   */
  645.   1, 0, F_EMPTY,    /*     ~     */
  646.   -1, 0, F_EMPTY,    /*       ~       */
  647.   1, 1, F_EMPTY,
  648.   1, -1, F_EMPTY,
  649.   -1, 1, F_EMPTY,
  650.   -1, -1, F_EMPTY,
  651.   -2, -1, F_EMPTY|F_BLACK,
  652.   2, -1, F_EMPTY|F_BLACK,
  653.   0, -2, F_EMPTY|F_BLACK|F_WHITE,
  654.   0, -3, F_OFF,
  655.  
  656.   PATTERN, 22, 33,    /*   ~ ~ #       */
  657.   0, 1, F_EMPTY,    /*   . . . . .   */
  658.   0, -1, F_EMPTY,    /*   . . $ . .   */
  659.   1, 0, F_EMPTY,    /*   . . . . .   */
  660.   -1, 0, F_EMPTY,    /*   . . . . .   */
  661.   1, 1, F_EMPTY,
  662.   1, -1, F_EMPTY,
  663.   -1, 1, F_EMPTY,
  664.   -1, -1, F_EMPTY,
  665.   2, -2, F_EMPTY,
  666.   -2, -2, F_EMPTY,
  667.   0, 2, F_BLACK,  
  668.   0, -2, F_EMPTY,  
  669.   2, 0, F_EMPTY,  
  670.   -2, 0, F_EMPTY,  
  671.   2, 1, F_EMPTY,
  672.   2, -1, F_EMPTY,
  673.   -2, 1, F_EMPTY,
  674.   -2, -1, F_EMPTY,
  675.   1, -2, F_EMPTY,
  676.   -1, -2, F_EMPTY,
  677.   -1, 2, F_EMPTY|F_WHITE,
  678.   -2, 2, F_EMPTY|F_WHITE,
  679.  
  680.   PATTEND
  681. };
  682.  
  683. /*a variable for debugging -- records the number of the pattern the */
  684. /* program thinks it has matched, so when the program makes a bizarre */
  685. /* move and claims that this helps it make shape, I can see what pattern */
  686. /* has gone wrong*/ 
  687. int patnum;
  688.  
  689. /*Where did the enemy last move?  This is used to help decide which patterns */
  690. /* are most important (try to leech off enemy's greater expertise).*/
  691. int lex, ley;
  692.  
  693. /*
  694. a table of moves the heuristics are ambivalent about, for 
  695. random selection
  696. */
  697. int goodmoves[2*EDGE*EDGE];
  698. int *pgoodmoves;    /*&next free space in goodmoves[]*/
  699.  
  700. fatal(message) char *message;
  701. /*Print an error message and abort program.*/
  702. { fprintf(stderr, "\n?!fatal error--%s\n", message);
  703.   /* *(int*)3; *//*Force a bus error so that Mark Williams C debugger works.*/
  704.   exit(1);
  705. }
  706.  
  707.  
  708. panic(message) char *message;
  709. /*Fatal error routine reserved for error conditions that ought not happen.*/
  710. { fprintf(stderr, "\n?!panic--%s\n", message);
  711.   exit(1);
  712. }
  713.  
  714.  
  715. int rng(n)  int n;
  716. /*Return a (slightly) random number from 0 to n-1.*/
  717. /*(This is a really crummy rng, it just keeps the 
  718. /*program's moves from all lying in a trivial pattern.)*/
  719. { static int seed= 0x1231;
  720.   int r;
  721.   seed= (seed*11+15) & 0x7FFF;
  722.   r= (((long)seed)*n)/(0x7FFF+1);
  723.   return r;
  724. }
  725.  
  726.  
  727. printgame()
  728. /*
  729. Output the game board theboard (with ko info from thegame) to the console.
  730. Currently the style is:
  731.  
  732.    a b c d e f g h j
  733.  1 . . . . . . . . . 1
  734.  2 . . . . . O O . . 2
  735.  3 . . O . . . # . . 3
  736.  4 . . O . . . # . . 4
  737.  5 O O ^ O . . . . . 5
  738.  6 . # O # . # # . . 6
  739.  7 . # # # . . . . . 7
  740.  8 . . . . . . . . . 8
  741.  9 . . . . . . . . . 9
  742.    a b c d e f g h j
  743.  
  744. where '^' is a ko, '#' is black, 'O' is white.
  745. */
  746. { register int x, y;
  747.  
  748.   printf("\n  ");
  749.   for(x=0; x<edge; ++x)
  750.     printf(" %c", lettercol(x));
  751.   printf("\n");
  752.   for(y=0; y<edge; ++y)
  753.   { printf("%2d ", 1+y);
  754.     for(x=0; x<edge; ++x)
  755.     { register int here= theboard[x][y];
  756.       printf( x!=(edge-1)?"%c ":"%c", 
  757.         (thegame.kox==x&&thegame.koy==y) ? '^' :
  758.         (EMPTY==here) ? '.' :
  759.         (WHITE==here) ? 'O' :
  760.         (BLACK==here) ? '#' :
  761.         panic("illegal board type in printboard()"));
  762.     }
  763.     printf(" %-2d\n", 1+y);
  764.   }
  765.   printf("  ");
  766.   for(x=0; x<edge; ++x)
  767.     printf(" %c", lettercol(x));
  768.   printf("\nGame turn= %d.  %s to play.\n",
  769.     thegame.tur, pname(thegame.pla));
  770. }
  771.  
  772.  
  773. initgame()
  774. { register int x, y, j, *h;
  775.  
  776. /*Clear the board.*/
  777.   for(x=0; x<edge; ++x)  for(y=0; y<edge; ++y)  
  778.     theboard[x][y]= EMPTY;
  779.  
  780. /*Initialize miscellaneous other stuff.*/
  781.   thegame.kox= thegame.koy= (-1);
  782.   thegame.tur= 1;
  783.   if(edge<sizeof(nhandicap)/sizeof(int) && nhandicap[edge]) 
  784.     thegame.pla= WHITE;
  785.   else
  786.     thegame.pla= BLACK;
  787.   thegame.qpa= 0;
  788.   lex= ley= (-1000);    /*nothing is near the enemy's last move*/
  789.  
  790.   if(edge<=sizeof(nhandicap)/sizeof(int)) /*If handicap defined for this board*/
  791.   { if(ofile&&nhandicap[edge])
  792. #ifdef  ADDED
  793.     switch (outputmode)
  794.     {
  795.     case WALLY_OUTPUT:
  796. #endif
  797.       fprintf(ofile, "handicap= %d:  ", nhandicap[edge]);
  798. #ifdef  ADDED
  799.       break;
  800.  
  801.     case MGT_OUTPUT:
  802.       fprintf(ofile, "AddBlack");
  803.       break;
  804.  
  805.     /* nothing to send for CAT_OUTPUT */
  806.     }
  807. #endif
  808.     for(h=handicap[edge],j=nhandicap[edge]; j; --j)
  809.     { x= *h++;
  810.       y= *h++;
  811.       assert(onboard(x,y));
  812.       assert(EMPTY==theboard[x][y]);
  813.       theboard[x][y]= BLACK;
  814. #ifdef  ADDED
  815.       if (ofile)
  816.       {
  817.         switch (outputmode)
  818.         {
  819.         case WALLY_OUTPUT:  /* should agree with #else below */
  820.           fprintf(ofile, "%c%d ", lettercol(x), 1+y);
  821.           break;
  822.  
  823.         case MGT_OUTPUT:
  824.           fprintf(ofile, "[%c%c]", M_LETTER(x), M_LETTER(y));
  825.           break;
  826.  
  827.         /* nothing to send for CAT_OUTPUT */
  828.         }
  829.       }
  830. #else
  831.       if(ofile) fprintf(ofile, "%c%d ", lettercol(x), 1+y);
  832. #endif
  833.     }
  834. #ifdef  ADDED
  835.     if (ofile)
  836.     {
  837.       switch (outputmode)
  838.       {
  839.       case WALLY_OUTPUT:  /* should agree with #else below */
  840.         fprintf(ofile, "\nboard= %d x %d\n", edge, edge);
  841.         break;
  842.  
  843.       case MGT_OUTPUT:
  844.         fputc('\n', ofile); /* boardsize sent earlier */
  845.         break;
  846.  
  847.       /* nothing to send for CAT_OUTPUT */
  848.       }
  849.     }
  850. #else
  851.     if(ofile) fprintf(ofile, "\nboard= %d x %d\n", edge, edge);
  852. #endif
  853.   }
  854.  
  855. }
  856.  
  857.  
  858. remove(x, y)  register int x, y;
  859. /*
  860. Recursively remove the stone at (x,y) and all stones in the same group
  861. from the board.
  862. */
  863. { register int color;
  864.   assert(onboard(x,y));
  865.   color= theboard[x][y];
  866.   assert(BLACK==color||WHITE==color);
  867.   theboard[x][y]= EMPTY;
  868.  
  869.   if(onboard(x, y+1) && color==theboard[x][y+1])
  870.     remove(x, y+1);
  871.   if(onboard(x, y-1) && color==theboard[x][y-1])
  872.     remove(x, y-1);
  873.   if(onboard(x+1, y) && color==theboard[x+1][y])
  874.     remove(x+1, y);
  875.   if(onboard(x-1, y) && color==theboard[x-1][y])
  876.     remove(x-1, y);
  877. }
  878.  
  879.  
  880. int capture(p, capx, capy)  int p, *capx, *capy;
  881. /*
  882. Remove all of player p's dead stones (as implied by results of makegroups())
  883. from the board.  Return # stones removed.  If any stones are removed, 
  884. theboard[][] is left inconsistent with groups[].
  885. *capx and *capy are set to the coordinates of a captured stone, if any, 
  886. so that if only one stone is captured, they may be used to set ko.
  887. */
  888. { register int j, rv=0;
  889.   register group *g;
  890.   for(g=groups,j=0; j<ngroups; ++g,++j)
  891.     if(p==g->color&&0==g->nliberties)
  892.     { rv += g->nstones; 
  893.       *capx= g->x; 
  894.       *capy= g->y;
  895.       remove(g->x, g->y);
  896.     }
  897.   return rv;
  898. }
  899.  
  900.  
  901. int colletter(letter)  register int letter;
  902. /*
  903. Return the column # (0 to edge-1) which corresponds to letter.
  904. Due to perversity of tournament organizers etc., 'i' or 'I' is 
  905. omitted, leading to an increase in complexity of this routine.
  906. Return (-1) on illegal input.
  907. */
  908. { register int result;
  909.  
  910.   if('a'<=letter&&letter<='z') 
  911.     result= letter-'a';
  912.   else if('A'<=letter&&letter<='Z') 
  913.     result= letter-'A';
  914.   else
  915.     return (-1);
  916.  
  917.   if(8>result)
  918.     ;
  919.   else if(8==result)
  920.     return (-1);
  921.   else
  922.     --result;
  923.   
  924.   if(result>=edge)
  925.     return (-1);
  926.   else
  927.     return result;
  928. }
  929.  
  930.  
  931. int getnb()
  932. /*Read and return the first nonblank character from the standard input.*/
  933. { int c;
  934.   do
  935.     c= getchar();
  936.   while(' '==c||'\n'==c||TAB==c);
  937.   return c;
  938. }
  939.  
  940.  
  941. int scanfcoo(x, y)  int *x, *y;
  942. /*
  943. Read a coordinate from the standard input and write it to *x and *y.  Like
  944. scanf, return 1 for success, 0 for failure, negative numbers for special
  945. moves, e.g. PASS and RESIGN. 
  946. On any input error, the function eats input up to the next newline.
  947. */
  948. {
  949.   int xx, yy, c1, c2;
  950.  
  951. /*Get first nonblank character of input, normally a letter code for a column.*/
  952.   c1= getnb();
  953.  
  954. /*Check for possible resignation (a '.' at the start of the input).*/
  955.   if('.'==c1)
  956.   { while('\n'!=getchar())    /*Skip to end of line.*/
  957.       ;
  958.     return RESIGN;
  959.   }
  960.  
  961. /*Check for possible "pass".*/
  962.   if('p'==lowercase(c1))
  963.   { c2= getchar();
  964.     if('a'!=lowercase(c2))
  965.       ungetc(c2, stdin);
  966.     else
  967.     { if((c2=getchar(),'s'!=lowercase(c2))||(c2=getchar(),'s'!=lowercase(c2)))
  968.       { ungetc(c2, stdin);
  969.     goto skipquit;
  970.       }
  971.       else
  972.         return PASS;
  973.   } } 
  974.   xx= colletter(c1);
  975.   if(1!=scanf("%d", &yy))
  976.   {
  977. skipquit:    /*Skip to the next newline and return failure.*/
  978.     while('\n'!=getchar()) 
  979.       ;
  980.     return 0;
  981.   }
  982.   if(0==onboard(xx,yy-1))    /*The -1 converts between C arrays starting */
  983.                 /* at 0 and human boards counting from 1.*/
  984.     goto skipquit;
  985.   else
  986.   { *x= xx;
  987.     *y= yy-1;
  988.     return 1;
  989.   }
  990. }
  991.  
  992.  
  993. movedone()
  994. /*
  995. Do everything which must be done to complete a move after the stone is 
  996. placed.
  997. */
  998. { thegame.pla= nextp(thegame.pla);  ++thegame.tur; }
  999.  
  1000.  
  1001. count(x, y, thisgroup, scratch, mark)  
  1002. register int x, y;  register group *thisgroup;  board scratch;  int mark;
  1003. /*
  1004. Recursively group together connected stones.  Three things must be done:
  1005.   (1) count liberties in thisgroup->nliberties,
  1006.   (2) count stones in thisgroup->nstones, and
  1007. We set scratch[][]= mark for each point and liberty of this group, 
  1008.   so that we only count each only once.  The calling routine must
  1009.   see to it that scratch[][]!=mark for all points and liberties that
  1010.   it wants counted.
  1011. */
  1012. { register int *bxy, *sxy; /*Common subexpressions to reduce array */
  1013.           /* arithmetic; they point to theboard[x][y] and scratch[x][y].*/
  1014.  
  1015. endrecurse:
  1016.   assert(onboard(x,y));
  1017.   assert(thisgroup->color==theboard[x][y]);
  1018.   assert(thisgroup->nstones>=0);
  1019.   assert(thisgroup->nliberties>=0);
  1020.   assert(mark!=scratch[x][y]);
  1021.  
  1022.     /*Set common subexpressions.*/
  1023.   bxy= &(theboard[x][y]);
  1024.   sxy= &(scratch[x][y]);
  1025.  
  1026.     /*Count the point (x,y) and make it a member of the group.*/
  1027.   ++(thisgroup->nstones);
  1028.   *sxy= mark;
  1029.  
  1030.     /*"Process" (x, y-1): should it be in the group, or a liberty, or */
  1031.     /* nothing?*/
  1032.   y= y-1;
  1033.   bxy -= 1;
  1034.   sxy -= 1;
  1035.   assert(&theboard[x][y]==bxy);
  1036.   assert(&scratch[x][y]==sxy);
  1037.   if(y>=0)
  1038.     if(thisgroup->color==*bxy)
  1039.     { if(*sxy!=mark)
  1040.         count(x, y, thisgroup, scratch, mark);
  1041.     }
  1042.     else if(EMPTY==*bxy)
  1043.     { if(*sxy!=mark)
  1044.       { *sxy=mark;
  1045.     ++(thisgroup->nliberties);
  1046.     } }
  1047.  
  1048.     /*Process (x, y+1).*/
  1049.   y= y+2;
  1050.   bxy += 2;
  1051.   sxy += 2;
  1052.   assert(&theboard[x][y]==bxy);
  1053.   assert(&scratch[x][y]==sxy);
  1054.   if(y<edge)
  1055.     if(thisgroup->color==*bxy)
  1056.     { if(*sxy!=mark)
  1057.         count(x, y, thisgroup, scratch, mark);
  1058.     }
  1059.     else if(EMPTY==*bxy)
  1060.     { if(*sxy!=mark)
  1061.       { *sxy=mark;
  1062.     ++(thisgroup->nliberties);
  1063.     } }
  1064.  
  1065.     /*Process (x-1, y).*/
  1066.   y= y-1;
  1067.   x= x-1;
  1068.   bxy -= EDGE+1;
  1069.   sxy -= EDGE+1;
  1070.   assert(&theboard[x][y]==bxy);
  1071.   assert(&scratch[x][y]==sxy);
  1072.   if(x>=0)
  1073.     if(thisgroup->color==*bxy)
  1074.     { if(*sxy!=mark)
  1075.         count(x, y, thisgroup, scratch, mark);
  1076.     }
  1077.     else if(EMPTY==*bxy)
  1078.     { if(*sxy!=mark)
  1079.       { *sxy=mark;
  1080.     ++(thisgroup->nliberties);
  1081.     } }
  1082.  
  1083.     /*Process (x+1, y).*/
  1084.   x= x+2;
  1085.   bxy += 2*EDGE;
  1086.   sxy += 2*EDGE;
  1087.   assert(&theboard[x][y]==bxy);
  1088.   assert(&scratch[x][y]==sxy);
  1089.   if(x<edge)
  1090.     if(thisgroup->color==*bxy)
  1091.     { if(*sxy!=mark)
  1092.         goto endrecurse;
  1093.     }
  1094.     else if(EMPTY==*bxy)
  1095.     { if(*sxy!=mark)
  1096.       { *sxy=mark;
  1097.     ++(thisgroup->nliberties);
  1098.     } }
  1099.  
  1100. }
  1101.  
  1102.  
  1103. makegroups()
  1104. /*Analyzes groupings of stones on board; sets groups[].*/
  1105.   register int x, y;    /*coords of point we are now assigning to a group*/
  1106.   board scratch;    /*scratch for count() to use to say if a point is */
  1107.             /* already counted*/
  1108.  
  1109.     /*Clear old groups[] table and scratch[][].*/
  1110.   ngroups= 0;
  1111.   { register int *s;
  1112.     for(s=scratch[0],x=0; x<EDGE*EDGE; ++x)
  1113.       *s++= 0;
  1114.   }
  1115.  
  1116.     /*Go through board[][] point by point.  Group any stone which has not */
  1117.     /* already been grouped (as indicated by negative scratch[][]).*/
  1118.   { register int *bxy= (int*)theboard, *sxy= (int*)scratch;
  1119.     register group *thisgroup=groups; 
  1120.     for(x=0; x<edge; ++x,bxy+=EDGE-edge,sxy+=EDGE-edge)  
  1121.       for(y=0; y<edge; ++y,++bxy,++sxy)
  1122.       { assert(&(theboard[x][y])==bxy);
  1123.     assert(&(scratch[x][y])==sxy);
  1124.     assert(&(groups[ngroups])==thisgroup);
  1125.         if((BLACK==*bxy||WHITE==*bxy) && 0==*sxy)
  1126.         { thisgroup->color= *bxy;
  1127.           thisgroup->x= x;
  1128.           thisgroup->y= y;
  1129.           thisgroup->nliberties= 0;
  1130.           thisgroup->nstones= 0;
  1131.           count(x, y, thisgroup, scratch, 1+thisgroup-groups);
  1132.           ++thisgroup;
  1133.           ++ngroups;
  1134.         } 
  1135.       }
  1136.   }
  1137. }
  1138.  
  1139.  
  1140. placestone(x, y, p)  int x, y, p;
  1141. /*
  1142. Put a stone for player p at (x,y) and remove all the captures which result.
  1143. Update ko information.
  1144. */
  1145. { int ncap, capx, capy;
  1146.   assert(onboard(x, y));
  1147.   assert(BLACK==p||WHITE==p);
  1148.   assert(EMPTY==theboard[x][y]);
  1149.  
  1150.   theboard[x][y]= p;
  1151.   makegroups();                /*Group all stones and count libs.*/
  1152.   ncap= capture(nextp(p), &capx, &capy);/*Remove p's opponent's dead stones.*/
  1153.   thegame.kox= thegame.koy= (-1);    /*Cancel any old ko.*/
  1154.   if(1==ncap)    /*If exactly one stone was captured, check for new ko.*/
  1155.   { register int j, *ip;  group g;
  1156.     board scratch;
  1157.     for(ip=(int*)scratch,j=EDGE*EDGE; j--; ) *ip++= 0;
  1158.     g.color= theboard[x][y];
  1159.     g.nstones= 0;
  1160.     g.nliberties= 0;
  1161.     g.x= x;
  1162.     g.y= y;
  1163.     count(x, y, &g, scratch, 1); /*Count stones and libs for capturing group.*/
  1164.     if(1==g.nstones && 1==g.nliberties)    /*If c.g. is a single stone in atari */
  1165.     { thegame.kox= capx; thegame.koy= capy; } /* then ko, so mark it.*/
  1166.   }
  1167.   if(ncap)        /*If any enemy stones were removed, */
  1168.     makegroups();    /* recalculate the board.*/
  1169.   ncap= capture(p, &capx, &capy);/*Remove any still-trapped stones (suicide).*/
  1170.   assert(WHITE==p||0==ncap);    /*Wally knows not to make suicides.*/
  1171. }
  1172.  
  1173.  
  1174.  
  1175. sortv(p, n)  group **p;  int n;
  1176. /*
  1177. Sort the table p[] or pointers to groups in order of vulnerability, 
  1178. most vulnerable first.
  1179. Currently this is the slow simple bubble sort we all know.
  1180. */
  1181. { register int uns;    /*flag that an unsorted pair was found last pass*/
  1182.   register group *t,    /*exchange temporary*/
  1183.          **ip;    /*pointer through p[]*/
  1184.   register int j;    /*loop index through p*/
  1185.  
  1186.   do
  1187.   { uns= 0;
  1188.     for(j=0,ip=p; j<n-1; ++j,++ip)
  1189.     { t= ip[1];
  1190.       if( t->nliberties< (*ip)->nliberties ||
  1191.      (t->nliberties==(*ip)->nliberties && t->nstones>(*ip)->nstones) )
  1192.       { uns= 1;
  1193.         ip[1]= *ip;
  1194.     *ip= t;
  1195.       }
  1196.     }
  1197.   } while(uns);
  1198.  
  1199. }
  1200.  
  1201.  
  1202. int subj_lib(x, y)  int x, y;
  1203. /*
  1204. Return the subjunctive liberties of the group created by a BLACK move at x, y,
  1205.  that is, how many liberties would it have after the move was made?
  1206. This is done shoddily, without considering the liberties created by 
  1207.  the disappearance of any groups captured by the move.
  1208. */
  1209. { board scratch;    /*parameter array of flags for count()*/
  1210.   group t;        /*parameter group for count()*/
  1211.  
  1212.   assert(onboard(x,y));
  1213.   assert(EMPTY==theboard[x][y]); /*Make sure we can undo by restoring EMPTY.*/
  1214.  
  1215.   theboard[x][y]= BLACK;    /*Temporarily place the stone in question.*/
  1216.  
  1217. /*Clear scratch[][] so count() works properly.*/
  1218.   { register int *s, j;
  1219.     for(j=EDGE*EDGE,s=(int*)scratch; j--; )
  1220.       *s++= 0;
  1221.   }
  1222.  
  1223. /*Make a fake group for the new stone to be part of -- this is */
  1224. /* a necessary parameter for count().*/
  1225.   t.color= BLACK;
  1226.   t.x= x;
  1227.   t.y= y;
  1228.   t.nliberties= 0;
  1229.   t.nstones= 0;
  1230.  
  1231. /*Show this little Potemkin village to the count().*/
  1232.   count(x, y, &t, scratch, 1);
  1233.  
  1234. /*Undo the temporary move (x,y).*/
  1235.   theboard[x][y]= EMPTY;
  1236.  
  1237. /*Return the result from count().*/
  1238.   return t.nliberties;
  1239.  
  1240. }
  1241.  
  1242.  
  1243. pattern1(u, masks, movehere)  int *u;  board masks, movehere;
  1244. /*
  1245. A routine called by pattern() to match possible moves to
  1246. tabulated patterns of specific orientation.  
  1247. *u gives the urgency of the best move found so far; we
  1248. are to ignore moves which are inferior to this.
  1249.  
  1250. If this move has not already been found (compare to the 
  1251. urgency value in movehere[]) then we set its urgency
  1252. value in *u and in movehere[], and put it into the table
  1253. goodmoves[].  If the move is better than any found before,
  1254. we put it at the beginning of the table; otherwise we
  1255. put it in at the pointer pgoodmoves.
  1256.  
  1257. masks[][] is an array which represents the pieces on the board, 
  1258. translated into bit masks by lookup in flookup[].
  1259.  
  1260. A late-breaking modification is that only the EMPTY points which have
  1261. movehere[][] set are tested, so that pattern() can be called to look for
  1262. contact plays or possibly other restricted sets which make good patterns.
  1263. An even later modification permits the use of movehere[][] to
  1264. tell the urgency of the best move which has been made to that
  1265. point.
  1266. */
  1267. { register int *is, *iis;/*pointers into patterns[]; or scratch*/
  1268.   register int j;    /*& into a particular pattern, # points remaining*/
  1269.   register int x, y;    /*current position we're trying to match pattern to*/
  1270.   register int xs, ys;    /*position of a point from a pattern*/
  1271.   int ua;        /*urgency and adjustment for this move*/
  1272.   int thispat;        /*which pattern in the table are we currently */
  1273.             /* trying to match?*/
  1274.  
  1275.  
  1276.   for(is=patterns,thispat=0; PATTERN==*is; is+= 3+3*(is[1]),++thispat)
  1277.   { for(x=0; x<edge; ++x)
  1278.       for(y=0; y<edge; ++y)
  1279.       { if(F_EMPTY==masks[x][y] && 0==ko(x,y) 
  1280.          &&(thegame.kox!=x||thegame.koy!=y) )
  1281.         { for(iis=is+1,j= *iis++,ua= *iis++; j; --j)
  1282.       { xs= *iis++;
  1283.         ys= *iis++;
  1284.         if(onboard(x+xs,y+ys))
  1285.         { if(0==(masks[x+xs][y+ys]&*iis++)) goto mismatch; }
  1286.         else
  1287.         { if(0==(F_OFF&*iis++)) goto mismatch; }
  1288.       }
  1289.       /*If we fall through here, then we matched a pattern.*/
  1290.       /*Compute adjusted urgency.*/
  1291.       if(abs(x-lex)<=1&&abs(y-ley)<=1) 
  1292.         ua-=4;                /*Important to oppose enemy's last move.*/
  1293.       for(xs=(-2); xs<=2; ++xs)  
  1294.         for(ys=(-2); ys<=2; ++ys)
  1295.           if(onboard(x+xs,y+ys))/*Important to move to */
  1296.             ++ua;            /* uncrowded parts of the board.*/
  1297.       if( ua<*u &&            /*If this pattern is most urgent so far */
  1298.           0==intoatari(x, y) )  /* and the move is not futile */
  1299.       { *u= ua;             /*Replace old */
  1300.         movehere[x][y]= ua;     /* urgency values.*/
  1301.         patnum= thispat;        /*Record pattern # for debugging.*/
  1302.         pgoodmoves= goodmoves;  /*Reinit goodmoves[].*/
  1303.         goto intogoodmoves;
  1304.       }
  1305.       else if( ua==*u &&        /*If there's no better pattern */
  1306.                ua<movehere[x][y] /* and it's the best move here */
  1307.            && !intoatari(x,y)) /*and not futile*/
  1308.       { movehere[x][y]= ua;    /*Mark as best move here.*/
  1309.       intogoodmoves: ;    /*Put it into goodmoves[].*/
  1310.         *pgoodmoves++= x;  *pgoodmoves++= y;
  1311.       }
  1312.         }
  1313.     mismatch: ;
  1314.       }
  1315.   }
  1316.   if(PATTEND!=*is)
  1317.   { fprintf(stderr, "?error in pattern table, pattern # %d\n", thispat);
  1318.     panic("programmer error in pattern table");
  1319.   }
  1320. }
  1321.  
  1322.  
  1323. pattern(chosenx, choseny, urgency, movehere)
  1324. int *chosenx, *choseny, *urgency;  board movehere;
  1325. /*
  1326. Try to find a good black move by matching to a table of patterns.  
  1327. Returns the urgency of the move; returns BIGU if no match found.
  1328.  
  1329. In order to match the patterns in all orientations, we 
  1330. reflect the entire table eight times, checking for a match each time.  
  1331. The reflections are
  1332.   (1)   y <-> edge-1-y    (across a mirror plane parallel to x-axis)
  1333.   (2)    x <-> edge-1-x    ( " y-axis)
  1334.   (3)   y <-> edge-1-y    ( " x-axis)
  1335.   (4)   x <-> y        ( " the line y=x)
  1336.   (5)   y <-> edge-1-y    (across a mirror plane parallel to x-axis)
  1337.   (6)    x <-> edge-1-x    ( " y-axis)
  1338.   (7)   y <-> edge-1-y    ( " x-axis)
  1339.   (8)   x <-> -y    ( " the line y=(-x))
  1340. Draw pictures if necessary to see how this works.
  1341. */
  1342.   register int x, y, t, j, *is;
  1343.   board scratch;
  1344.  
  1345.  
  1346. /*Translate the board to flags for easy comparison with pattern table.*/
  1347.   for(x=0; x<edge; ++x) 
  1348.     for(y=0; y<edge; ++y)
  1349.       scratch[x][y]= flookup[theboard[x][y]]; 
  1350.  
  1351.   *urgency= BIGU;        /*No big move so far.*/
  1352.   pgoodmoves= goodmoves;    /*No moves so far.*/
  1353.   patnum= (-1);            /*For debugging: no pattern # so far.*/
  1354.  
  1355.   pattern1(urgency, scratch, movehere); 
  1356.                 /*Find matches to untransformed table.*/
  1357.  
  1358. /*Invert y coordinates in pattern table.*/
  1359.   for(is=patterns; PATTERN==*is; )
  1360.   { for(j= *++is,is+=2; j--; )
  1361.     { is += 1;
  1362.       *is= (-*is);
  1363.       is += 2;
  1364.     }
  1365.   }
  1366.   assert(PATTEND==*is);
  1367.  
  1368.  
  1369.   pattern1(urgency, scratch, movehere); 
  1370.                 /*Find matches to transformed table.*/
  1371.  
  1372. /*Invert x coordinates in pattern table.*/
  1373.   for(is=patterns; PATTERN==*is; )
  1374.   { for(j= *++is,is+=2; j--; )
  1375.     { ;
  1376.       *is= (-*is);
  1377.       is += 3;
  1378.     }
  1379.   }
  1380.   assert(PATTEND==*is);
  1381.  
  1382.   pattern1(urgency, scratch, movehere); 
  1383.                 /*Find matches to transformed table.*/
  1384.  
  1385. /*Invert y coordinates in pattern table.*/
  1386.   for(is=patterns; PATTERN==*is; )
  1387.   { for(j= *++is,is+=2; j--; )
  1388.     { is += 1;
  1389.       *is= (-*is);
  1390.       is += 2;
  1391.     }
  1392.   }
  1393.   assert(PATTEND==*is);
  1394.     
  1395.   pattern1(urgency, scratch, movehere); 
  1396.                 /*Find matches to transformed table.*/
  1397.  
  1398. /*Exchange x and y coordinates in pattern table.*/
  1399.   for(is=patterns; PATTERN==*is; )
  1400.   { for(j= *++is,is+=2; j--; )
  1401.     { t= *is;
  1402.       *is= is[1];
  1403.       is[1]= t;
  1404.       is += 3;
  1405.     }
  1406.   }
  1407.   assert(PATTEND==*is);
  1408.     
  1409.   pattern1(urgency, scratch, movehere); 
  1410.                 /*Find matches to transformed table.*/
  1411.  
  1412. /*Invert y coordinates in pattern table.*/
  1413.   for(is=patterns; PATTERN==*is; )
  1414.   { for(j= *++is,is+=2; j--; )
  1415.     { is += 1;
  1416.       *is= (-*is);
  1417.       is += 2;
  1418.     }
  1419.   }
  1420.   assert(PATTEND==*is);
  1421.     
  1422.   pattern1(urgency, scratch, movehere); 
  1423.                 /*Find matches to transformed table.*/
  1424.  
  1425. /*Invert x coordinates in pattern table.*/
  1426.   for(is=patterns; PATTERN==*is; )
  1427.   { for(j= *++is,is+=2; j--; )
  1428.     { ;
  1429.       *is= (-*is);
  1430.       is += 3;
  1431.     }
  1432.   }
  1433.   assert(PATTEND==*is);
  1434.  
  1435.   pattern1(urgency, scratch, movehere); 
  1436.                 /*Find matches to transformed table.*/
  1437.  
  1438. /*Invert y coordinates in pattern table.*/
  1439.   for(is=patterns; PATTERN==*is; )
  1440.   { for(j= *++is,is+=2; j--; )
  1441.     { is += 1;
  1442.       *is= (-*is);
  1443.       is += 2;
  1444.     }
  1445.   }
  1446.   assert(PATTEND==*is);
  1447.     
  1448.   pattern1(urgency, scratch, movehere); 
  1449.                 /*Find matches to transformed table.*/
  1450.  
  1451. /*Exchange x and -y coordinates in pattern table.*/
  1452.   for(is=patterns; PATTERN==*is; )
  1453.   { for(j= *++is,is+=2; j--; )
  1454.     { t= (-*is);
  1455.       *is= (-is[1]);
  1456.       is[1]= t;
  1457.       is += 3;
  1458.     }
  1459.   }
  1460.   assert(PATTEND==*is);
  1461.  
  1462. /*Try to pick a move from the table of equally good ones.*/
  1463.   { int nmoves= (pgoodmoves-goodmoves)/2;
  1464.     if(0==nmoves) return;
  1465.     else
  1466.     { int whichmove= rng(nmoves);
  1467.       *chosenx= goodmoves[2*whichmove];
  1468.       *choseny= goodmoves[2*whichmove+1];
  1469.     }
  1470.   }
  1471.  
  1472. /*We'd better not have decided on an illegal move.*/
  1473. #if ASSERT
  1474.   if( *urgency<BIGU )
  1475.     if( EMPTY!=theboard[*chosenx][*choseny] || ko(*chosenx,*choseny) )
  1476.       panic("illegal move selected in pattern()");
  1477. #endif
  1478.  
  1479. }
  1480.  
  1481.  
  1482. int attack(g, rx, ry, ml)  group *g;  int *rx, *ry, ml;
  1483. /*
  1484. Set *rx and *ry to a move which attacks group *g and still has
  1485. at least ml liberties.
  1486.  
  1487. This routine tries to return the "best" contact play if several are possible.
  1488. This is currently implemented as the one as close to the 
  1489.  (2.9)-th line as possible, that is, one on the third line is best,
  1490.  then one on the fourth, then one on the second, then one on the fifth,
  1491.  then etc.
  1492.  
  1493. Return TRUE on failure.
  1494. */
  1495. { int bestx, besty;    /*best contact move found so far*/
  1496.   int edist;        /*10*distance of this play from (2.9)-st line*/
  1497.   register int x, y;
  1498.     
  1499.   board scratch;
  1500.  
  1501. /*Clear scratch[][] so that count() can work.*/
  1502.   { register int j, *is;
  1503.     for(j=EDGE*EDGE,is=(int*)scratch;  j--; )
  1504.       *is++= 0;
  1505.   }
  1506.  
  1507. /*Set scratch[][] again for the stones of the group, and recalculate the */
  1508. /* number of liberties of the group.  Also set scratch[][] for all the EMPTY */
  1509. /* points which are contact moves.*/
  1510.   g->nstones= 0;    /*Clear these before */    
  1511.   g->nliberties= 0;    /* passing to count, which increments them.*/
  1512.   count(g->x, g->y, g, scratch, 1);
  1513.  
  1514. /*Print out scratch[][] as 9x9 table.*/
  1515.   if(debugattack) {
  1516.     printf("$In attack after count(), board and scratch are:\n");
  1517.     for(y=edge-1; y>=0; --y)
  1518.     { printf("$");
  1519.       for(x=0; x<edge; ++x)
  1520.       { register int c, t=theboard[x][y];
  1521.         if(EMPTY==t) c= '.';
  1522.         else if(BLACK==t) c= '#';
  1523.         else if(WHITE==t) c= 'O';
  1524.         else c= '?';
  1525.         printf("%c%d ", c, scratch[x][y]);
  1526.       }
  1527.       printf("\n");
  1528.     }
  1529.   }
  1530.  
  1531. /*Check that there are enough liberties to find a contact play.*/
  1532.   assert(g->nliberties>=0);
  1533.  
  1534. /*Look for the best adjacent point.*/
  1535.   edist= edge*10;    /*We haven't found a point near the (2.9)-th line yet.*/
  1536.   for(x=0; x<edge; ++x)              /*For */
  1537.     for(y=0; y<edge; ++y)            /* all */
  1538.       if(EMPTY==theboard[x][y] && scratch[x][y]    /*  contact points*/
  1539.        && (thegame.kox!=x||thegame.koy!=y) )    /*   which don't violate ko */
  1540.         if(subj_lib(x,y)>=ml)            /*    if not too suicidal*/
  1541.     { register int toedge= x;    /*distance to edge of board*/
  1542.       if(toedge>edge-1-x) toedge= edge-1-x;
  1543.           if(toedge>y) toedge= y;
  1544.           if(toedge>edge-1-y) toedge= edge-1-y;
  1545.           if(debugattack)
  1546.             fprintf(stderr, "$Looking at %d,%d, toedge=%d, abs=%d.\n", 
  1547.         x, y, toedge, abs(10*toedge-21));
  1548.       if(abs(10*toedge-19)<edist)    /*If closer to 2.9th line than before*/
  1549.           { edist= abs(10*toedge-21);    /* record */
  1550.             if(debugattack) fprintf(stderr, "$Replacing edist.\n");
  1551.         bestx= x;  besty= y;    /*  as the new best so far.*/
  1552.           }
  1553.           else
  1554.         if(debugattack) fprintf(stderr, "$Not replacing edist=%d.\n", edist);
  1555.         }
  1556.  
  1557.   if(debugattack) fprintf(stderr, "$Edist= %d.\n", edist);
  1558.  
  1559. /*Return best result, if any.*/
  1560.   if(edist<edge*10)            /*If some good contact play found */
  1561.   { *rx= bestx;  *ry= besty;          /* return it */
  1562.     if(debugattack) fprintf(stderr, "$Returning 0.\n");
  1563.     return 0;                /*  and success */
  1564.   }
  1565.   else
  1566.   { if(debugattack) fprintf(stderr, "$Returning 1.\n");
  1567.     return 1;
  1568. } }
  1569.  
  1570.  
  1571. int escape(g, rx, ry)  group *g;  int *rx, *ry;
  1572. /*
  1573. Set *rx and *ry to a play which lets group *g escape from atari.
  1574. */
  1575. { register int x, y;
  1576.     
  1577.   board scratch;
  1578.  
  1579. /*Clear scratch[][] so that count() can work.*/
  1580.   { register int j, *is;
  1581.     for(j=EDGE*EDGE,is=(int*)scratch;  j--; )
  1582.       *is++= 0;
  1583.   }
  1584.  
  1585. /*Set scratch[][] again for the stones of the group, and recalculate the */
  1586. /* number of liberties of the group.  Also set scratch[][] for all the EMPTY */
  1587. /* points which are contact moves.*/
  1588.   g->nstones= 0;    /*Clear these before */    
  1589.   g->nliberties= 0;    /* passing to count, which increments them.*/
  1590.   count(g->x, g->y, g, scratch, 1);
  1591.  
  1592. /*Check that there are enough liberties to find a contact play.*/
  1593.   assert(g->nliberties>=0);
  1594.  
  1595. /*Return any point which succeeds.*/
  1596.   for(x=0; x<edge; ++x)              /*For */
  1597.     for(y=0; y<edge; ++y)            /* each */
  1598.       if(EMPTY==theboard[x][y] && scratch[x][y] /*  contact point */
  1599.        &&(thegame.kox!=x&&thegame.koy!=y) )    /*   which is not ko */
  1600.         if(0==intoatari(x,y))            /*    if not into atari */
  1601.     { *rx= x;  *ry= y;  return 0; }        /*     then return it.*/
  1602.  
  1603. /*Otherwise return failure.*/
  1604.   return 1;
  1605. }
  1606.  
  1607.  
  1608. mymove()
  1609. /*Calculate and execute and print out the computer's move.*/
  1610. {
  1611.   register int j;  register group *g; /*index and pointer through groups[]*/
  1612.   int x, y;            /*coords of the move selected*/
  1613.   group *gt[EDGE*EDGE];        /*table of &groups in order of vulnerability*/
  1614.   group **fs, **es;        /*pointers into gt: start of friendly and */
  1615.                 /* enemy tables*/
  1616.   register group **igt;        /*scratch pointer through gt[]*/
  1617.   int nf, ne;            /*number of enemy and friendly groups*/
  1618.   int upattern, patternx, patterny;
  1619.   board scratch;
  1620.  
  1621. /*Find the most urgent move to improve our shape.*/
  1622. /*First say that all moves are to be considered.*/
  1623.   { register int *ip;
  1624.     for(ip=(int*)scratch,j=EDGE*EDGE; j--; )
  1625.       *ip++= BIGU;
  1626.   }
  1627. /*Then call pattern search.*/
  1628.   pattern(&patternx, &patterny, &upattern, scratch);
  1629.  
  1630. /*Make tables of friendly and enemy groups in gt[] at *fs and *es.*/
  1631.   for(j=0,g=groups,nf=0,fs=igt=gt; j<ngroups; ++j,++g)
  1632.     if(BLACK==g->color)
  1633.     { ++nf;
  1634.       *igt++= g;
  1635.     }
  1636.   for(j=0,g=groups,ne=0,es=igt; j<ngroups; ++j,++g)
  1637.     if(WHITE==g->color)
  1638.     { ++ne;
  1639.       *igt++= g;
  1640.     }
  1641.  
  1642. /*Sort the tables in order of vulnerability to attack.*/
  1643.   sortv(fs, nf);
  1644.   sortv(es, ne);
  1645.  
  1646. /*Consider extremely urgent pattern moves.*/
  1647.   if(upattern<16)
  1648.   { 
  1649.   movepattern:
  1650.     if(debugattack)
  1651.       printf("$making pattern, pattern #=%d, urgency=%d.\n", patnum, upattern);
  1652.     x= patternx;
  1653.     y= patterny;
  1654.     goto movexy;
  1655.   }    
  1656. /*Capture the enemy!*/
  1657.   while(ne && 1==(*es)->nliberties)
  1658.   { if(0==attack(*es, &x, &y, 0))
  1659.     { if(debugattack) printf("$Capturing the enemy.\n");
  1660.       goto movexy;
  1661.     }
  1662.     else /*(This case comes up if we can't capture because of ko.)*/
  1663.     { ++es; --ne; }        /*Go on to next most vulnerable group.*/
  1664.   }
  1665.   if(upattern<24) goto movepattern;
  1666. /*If we can't do that, then try to protect ourself.  But as per Dr. Millen, */
  1667. /* don't risk everything crawling along the edge without lookahead.*/
  1668. /*However, we have a more powerful computer than the good doctor, so we */
  1669. /* can afford to check another condition: if crawling connects to a healthy */
  1670. /* group immediately (as when the program makes a pattern match with */
  1671. /*    O O #    */
  1672. /*    . . O .    */
  1673. /*    ~ ~ ~ ~ */
  1674. /* where '~' is off the board, then is attacked with */
  1675. /*    O O #   */
  1676. /*    . . O # */
  1677. /*    ~ ~ ~ + */
  1678. /* it seems to make no sense to prohibit the program from defending with */
  1679. /*    O O #   */
  1680. /*    . O O # */
  1681. /*    ~ ~ ~ ~ */
  1682. /* ..  so we *don't* prohibit it.*/
  1683.   while(nf && 1==(*fs)->nliberties)
  1684.   { if(escape(*fs, &x, &y))    /*If we can't see how to escape */
  1685.     { ++fs; --nf; }        /* go on to next friendly group, */
  1686.     else            /*  otherwise */
  1687.     { if((0==x||edge-1==x||0==y||edge-1==y) && /* if crawling */
  1688.      (2>=subj_lib(x,y)) )    /* and not connecting to strong group */
  1689.       { ++fs; --nf;  continue; } /* this is probably not a good move */
  1690.       else            /* but if not crawling or connecting to */
  1691.                 /* a strong group, go for it.*/
  1692.       if(debugattack)
  1693.         printf("$Protecting a friendly group from imminent capture.\n");
  1694.       goto movexy;
  1695.     }
  1696.   }
  1697.   if(upattern<34) goto movepattern;
  1698. /*Try putting the enemy in atari.*/
  1699.   while(ne && 2==(*es)->nliberties)    /*For all vulnerable enemy groups */
  1700.   { if(attack(*es, &x, &y, 2))        /* if we can't see how to attack */
  1701.     { ne--; ++es; }            /*  go on to the next enemy group, */
  1702.     else                /*   otherwise */
  1703.     { if(debugattack)
  1704.         printf("$Putting an enemy group into atari.\n");
  1705.       goto movexy;            /*    attack the group.*/
  1706.     }
  1707.   }
  1708.   if(upattern<BIGU) goto movepattern;
  1709. /*Try to harass the most vulnerable enemy group.*/
  1710.   while(ne)                /*For all remaining enemy groups */
  1711.   { if(attack(*es, &x, &y, 3))    /* if we can't see how to attack safely */
  1712.     { --ne; ++es; }            /*  go on to next enemy group*/
  1713.     else                /*   otherwise*/
  1714.     { if(debugattack)
  1715.         printf("$Harassing the most vulnerable enemy group.\n");
  1716.       goto movexy;            /*    attack it*/
  1717.     }
  1718.   }
  1719. #if 0 /*This seems to lose points.  Lets see how we do without it.*/
  1720. /*Move randomly adjacent to no stones or edges.*/
  1721.   for(x=1; x<edge-1; ++x)  for(y=1; y<edge-1; ++y)
  1722.     if( EMPTY==theboard[x][y] &&
  1723.     EMPTY==theboard[x][y-1] && EMPTY==theboard[x][y+1] && 
  1724.         EMPTY==theboard[x-1][y] && EMPTY==theboard[x+1][y] )
  1725.     { if(debugattack)
  1726.         printf("$Moving randomly to fill space.\n");*/
  1727.       goto movexy;
  1728.     }
  1729. #endif
  1730. /*If nothing else comes to mind, pass.*/
  1731.   printf("%s passes.\n", progname);
  1732.   if(ofile)
  1733. #ifdef  ADDED
  1734.    switch (outputmode)
  1735.    {
  1736.    case WALLY_OUTPUT:
  1737. #endif
  1738.     fprintf(ofile, "%d: pass\n", thegame.tur);
  1739. #ifdef  ADDED
  1740.     break;
  1741.  
  1742.    case MGT_OUTPUT:
  1743.     fprintf(ofile, ";\nComment[Black passes]\n");
  1744.     break;
  1745.  
  1746.    /* nothing to do for CAT_OUTPUT */
  1747.    }
  1748. #endif
  1749.   thegame.kox= thegame.koy= (-1);
  1750.   movedone();
  1751.   if(thegame.qpa) return BOTHPASS;
  1752.   else
  1753.   { thegame.qpa= 1;
  1754.     return PASS;  
  1755.   }
  1756.  
  1757. movexy:
  1758.   printf("%s moves to %c%d.\n", progname, lettercol(x), y+1);
  1759.   fflush(stdout);
  1760.   if(ofile)
  1761. #ifdef  ADDED
  1762.    switch (outputmode)
  1763.    {
  1764.    case WALLY_OUTPUT:
  1765. #endif
  1766.     fprintf(ofile, "%d: %c%d\n", thegame.tur, lettercol(x), y+1);
  1767. #ifdef  ADDED
  1768.     break;
  1769.  
  1770.    case MGT_OUTPUT:
  1771.     fprintf(ofile, ";\nComment[%d: Black: %c%d]\nBlack[%c%c]\n",
  1772.     thegame.tur, lettercol(x), y+1, M_LETTER(x), M_LETTER(y));
  1773.     break;
  1774.  
  1775.   /* nothing for CAT_OUTPUT as it will be recalculated */
  1776.   }
  1777. #endif
  1778.   placestone(x, y, BLACK);
  1779.   thegame.qpa= 0;
  1780.   movedone();
  1781.   return 0;
  1782. }
  1783.  
  1784.  
  1785. enemymove()
  1786. /*Read and execute opponent's move.*/
  1787. { int x, y;    /*coordinates of move*/
  1788.   int s;    /*return value of scanfcoo()*/
  1789. endrecurse:
  1790.   printgame();
  1791.   printf("Please input your move (%s #%d): ", pname(thegame.pla), thegame.tur);
  1792.   s= scanfcoo(&x, &y);    /*Try to get a move.*/
  1793.   if(RESIGN==s)        /*If opponent resigns*/
  1794. #ifdef  ADDED
  1795.   {
  1796.     if (ofile)
  1797.     {
  1798.       switch (outputmode)
  1799.       {
  1800.       case WALLY_OUTPUT:  /* should agree with #else below */
  1801.         fprintf(ofile, "%d: resigns\n", thegame.tur);
  1802.         break;
  1803.  
  1804.       case MGT_OUTPUT:
  1805.         fprintf(ofile, ";\nComment[White resigns]\n");
  1806.         break;
  1807.  
  1808.       case CAT_OUTPUT:
  1809.         fprintf(ofile, ".\n");
  1810.         break;
  1811.       }
  1812.     }
  1813. #else
  1814.   { if(ofile)  fprintf(ofile, "%d: resigns\n", thegame.tur);
  1815. #endif
  1816.     return RESIGN;
  1817.   }
  1818.   if(PASS==s)        /*If opponent passes*/
  1819. #ifdef  ADDED
  1820.   {
  1821.     if (ofile)
  1822.     {
  1823.       switch (outputmode)
  1824.       {
  1825.       case WALLY_OUTPUT:  /* should agree with #else below */
  1826.         fprintf(ofile, "%d: pass\n", thegame.tur);
  1827.         break;
  1828.  
  1829.       case MGT_OUTPUT:
  1830.         fprintf(ofile, ";\nComment[White passes]\n");
  1831.         break;
  1832.  
  1833.       case CAT_OUTPUT:
  1834.         fprintf(ofile, "pass\n");
  1835.         break;
  1836.       }
  1837.     }
  1838. #else
  1839.   { if(ofile)  fprintf(ofile, "%d: pass\n", thegame.tur);
  1840. #endif
  1841.     movedone();
  1842.     thegame.kox= thegame.koy= (-1);
  1843.     ley= ley= (-1000);    /*'way off the board*/
  1844.     if(thegame.qpa) return BOTHPASS;
  1845.     else
  1846.     { thegame.qpa= 1;
  1847.       return PASS;
  1848.   } }
  1849.   if( 0==s )
  1850.   { printf("Please try again.  Input your move as a letter for the column, \n");
  1851.     printf(" followed by a number for the row number.\n");
  1852.     goto endrecurse;
  1853.   }
  1854.   if( 0==onboard(x,y) )
  1855.   { printf("Only moves which are on the board are legal.  Please try again.\n");
  1856.     goto endrecurse;
  1857.   }
  1858.   if( EMPTY!=theboard[x][y] ) 
  1859.   { printf("You cannot stack a stone on another.  ");
  1860. pleasetryanothermove:
  1861.     printf("Please try another move.\n");
  1862.     goto endrecurse;
  1863.   } 
  1864.   if(ko(x,y))
  1865.   { printf("That move would violate the rule of ko.  ");
  1866.     goto pleasetryanothermove;
  1867.   }
  1868.   placestone(x, y, thegame.pla);
  1869.   thegame.qpa= 0;
  1870.   if(ofile)
  1871. #ifdef  ADDED
  1872.    switch (outputmode)
  1873.    {
  1874.    case WALLY_OUTPUT:
  1875. #endif
  1876.     fprintf(ofile, "%d: %c%d\n", thegame.tur, lettercol(x), y+1);
  1877. #ifdef  ADDED
  1878.     break;
  1879.  
  1880.    case MGT_OUTPUT:
  1881.     fprintf(ofile, ";\nComment[%d: White: %c%d]\nWhite[%c%c]\n",
  1882.     thegame.tur, lettercol(x), y+1, M_LETTER(x), M_LETTER(y));
  1883.     break;
  1884.  
  1885.    case CAT_OUTPUT:
  1886.     fprintf(ofile, "%c%d\n", lettercol(x), y+1);
  1887.     break;
  1888.    }
  1889. #endif
  1890.   movedone();
  1891.   return 0;  
  1892. }
  1893.  
  1894.  
  1895. fscore(file, territory)  FILE *file;  int territory[NPLAYERS];
  1896. {
  1897.   register int j;
  1898.  
  1899.   fprintf(file, "(the end of the game)\n");
  1900.   fprintf(file, "Final score is:\n");
  1901.   for(j=0; j<NPLAYERS; ++j)  
  1902.     fprintf(file, "%s has %d territory.\n", 
  1903.             BLACK==j?"Black":"White", territory[j]);
  1904.   j= territory[BLACK]-territory[WHITE];
  1905.   if(0==j)
  1906.     fprintf(file, "(a tie)\n");
  1907.   else if(j>0)
  1908.     fprintf(file, "(Black wins.)\n");
  1909.   else
  1910.     fprintf(file, "(White wins.)\n");
  1911.  
  1912. }
  1913.  
  1914.  
  1915. int ist(x, y, n, scratch)  register int x, y, n;  board scratch;
  1916. /*This is the recursive part of isterritory().*/
  1917. {
  1918.   assert(onboard(x,y));
  1919.   assert(EMPTY==theboard[x][y]);
  1920.   assert(0==scratch[x][y]);
  1921.   scratch[x][y]= 1;
  1922.  
  1923.   x= x+1;
  1924.   if(onboard(x,y))
  1925.   { if(EMPTY==theboard[x][y])
  1926.     { if(0==scratch[x][y] && 0==ist(x, y, n, scratch))
  1927.         return 0;
  1928.     }
  1929.     else if(n==theboard[x][y])
  1930.       return 0;
  1931.   } 
  1932.  
  1933.   x= x-2;
  1934.   if(onboard(x,y))
  1935.   { if(EMPTY==theboard[x][y])
  1936.     { if(0==scratch[x][y] && 0==ist(x, y, n, scratch))
  1937.         return 0;
  1938.     }
  1939.     else if(n==theboard[x][y])
  1940.       return 0;
  1941.   } 
  1942.  
  1943.   x= x+1;
  1944.   y= y+1;
  1945.   if(onboard(x,y))
  1946.   { if(EMPTY==theboard[x][y])
  1947.     { if(0==scratch[x][y] && 0==ist(x, y, n, scratch))
  1948.         return 0;
  1949.     }
  1950.     else if(n==theboard[x][y])
  1951.       return 0;
  1952.   } 
  1953.  
  1954.   y= y-2;
  1955.   if(onboard(x,y))
  1956.   { if(EMPTY==theboard[x][y])
  1957.     { if(0==scratch[x][y] && 0==ist(x, y, n, scratch))
  1958.         return 0;
  1959.     }
  1960.     else if(n==theboard[x][y])
  1961.       return 0;
  1962.   } 
  1963.  
  1964.   return 1;
  1965.  
  1966. }
  1967.  
  1968.  
  1969. int isterritory(x, y, p)  register int x, y, p;
  1970. /*
  1971. Return TRUE if the EMPTY point x, y is to be counted as territory for
  1972. player p.  This is only called at the end of the game, and I see no
  1973. reason why it can't be slow.
  1974.  
  1975. I don't understand the (Ing?) fractional point rules, so I don't implement them.
  1976.  An empty point counts as territory only if only one player has stones adjacent
  1977.  to the block of empty spaces to which it belongs.
  1978. */
  1979. {
  1980.   board scratch;
  1981.  
  1982.   assert(onboard(x,y));
  1983.   assert(EMPTY==theboard[x][y]);
  1984.  
  1985. /*Clear scratch[].*/
  1986.   { register int x, y;
  1987.     for(x=0; x<edge; ++x)  for(y=0; y<edge; ++y)
  1988.       scratch[x][y]= 0;
  1989.   }
  1990.  
  1991. /*Decide recursively.*/
  1992.   return ist(x, y, nextp(p), scratch);
  1993.  
  1994. }
  1995.  
  1996.  
  1997. score()
  1998. /*Compute and output the final game score.  Use Chinese rules, of course.*/
  1999. {
  2000.   register int x, y, p;
  2001.   int territory[NPLAYERS];    /*each player's territory*/
  2002.  
  2003. /*Count territories.*/
  2004.   for(p=0; p<NPLAYERS; ++p) 
  2005.   { territory[p]= 0;
  2006.     for(x=0; x<edge; ++x)  for(y=0; y<edge; ++y)
  2007.       if(p==theboard[x][y]||EMPTY==theboard[x][y]&&isterritory(x,y,p))
  2008.     ++territory[p];
  2009.   }
  2010.  
  2011. /*Output results.*/
  2012.   fscore(stdout, territory);
  2013.   if(ofile)
  2014. #ifdef  ADDED
  2015.    switch (outputmode)
  2016.    {
  2017.    case WALLY_OUTPUT:
  2018. #endif
  2019.     fscore(ofile, territory);
  2020. #ifdef    ADDED
  2021.     break;
  2022.  
  2023.    case MGT_OUTPUT:
  2024.     fprintf(ofile, ";\nComment[");
  2025.     fscore(ofile, territory);
  2026.     fprintf(ofile, "]\n");
  2027.     break;
  2028.  
  2029.    /* nothing to write for CAT_OUTPUT */
  2030.    }
  2031. #endif
  2032.  
  2033. }
  2034.  
  2035.  
  2036. main(argc, argv)  int argc;  char *argv[];
  2037. { int maybe= 0;    /*possible input board size*/
  2038.   int rvalue;    /*return values from enemymove() and mymove()*/
  2039.  
  2040. #ifdef    ADDED
  2041.   long secs, time();
  2042.   char hname[80], *ctime();
  2043. #endif
  2044.  
  2045. /*Process command line arguments.*/
  2046.   argv++;    /*Skip argv[0]; Mark Williams C doesn't seem to set it.*/
  2047.   for( ; --argc; ++argv)
  2048.   { if(1==sscanf(*argv, "%d", &maybe))
  2049.     { if(maybe<7 || maybe>EDGE) fatal("board size out of range on input line");
  2050.       edge= maybe;
  2051.     }
  2052.     else if(0==strcmp(*argv,"-even"))    /*if we are to play an even game*/
  2053.       evenmode= 1;
  2054. #ifdef  ADDED
  2055.     else if (strcmp(*argv, "-d") == 0)
  2056.       debugattack = 1;
  2057.     else if (strcmp(*argv, "-mgt") == 0)
  2058.       outputmode = MGT_OUTPUT;
  2059.     else if (strcmp(*argv, "-cat") == 0)
  2060.       outputmode = CAT_OUTPUT;
  2061. #endif
  2062.     else
  2063. #ifdef    ADDED
  2064.     {
  2065. #else
  2066.     { char hname[80];
  2067. #endif
  2068.       if(0!=ofname) fatal("duplicate filenames in command line");
  2069.       ofname= *argv;
  2070.       ofile= fopen(ofname, "w");      
  2071.       if(0==ofile) fatal("unable to open output file");
  2072. #ifndef ADDED
  2073.       printf("What is the name of my opponent? (for the game record)\n");
  2074.       gets(hname);
  2075.       fprintf(ofile, "%s (black) vs. %s (white)\n", progname, hname);
  2076. #endif
  2077.     }
  2078.   }
  2079. #ifdef  ADDED
  2080.   if (ofile == 0)
  2081.   {
  2082.     if (outputmode != WALLY_OUTPUT)
  2083.     {
  2084.       fprintf(stderr, "%s: output file needed for -mgt or -cat\n", progname);
  2085.       exit(1);
  2086.     }
  2087.   }
  2088.   else
  2089.   {
  2090.     if (outputmode != CAT_OUTPUT)
  2091.     {
  2092.       printf("What is the name of my opponent?  ");
  2093.       gets(hname);
  2094.     }
  2095.  
  2096.     switch (outputmode)
  2097.     {
  2098.     case WALLY_OUTPUT:  /* should match that in #ifndef above */
  2099.       fprintf(ofile, "%s (black) vs. %s (white)\n", progname, hname);
  2100.       break;
  2101.  
  2102.     case MGT_OUTPUT:
  2103.       time(&secs);
  2104.       fprintf(ofile, "(\n;\nGaMe[1]\nSize[%d]\nVieW[]\nBlackSpec[1]\n", edge);
  2105.       fprintf(ofile, "WhiteSpec[1]\nFileFormat[1]\nPLayer[]\n");
  2106.       fprintf(ofile, "Comment[Black: %s\nWhite: %s\n\nDate:  %s",
  2107.     progname, hname, ctime(&secs));
  2108.       fprintf(ofile, "Size:  %d x %d]\n", edge, edge);
  2109.  
  2110.     /* CAT_OUTPUT doesn't require any of this */
  2111.     }
  2112.   }
  2113. #endif
  2114.   if(evenmode) nhandicap[edge]= 0;
  2115.  
  2116. /*Make a brief explanation.*/
  2117.   printf("%s\n%s\n",
  2118.     "This program plays (poorly) the oriental game of Go, also",
  2119.     "known as wei-chi.");
  2120.  
  2121. /*Play the game.*/
  2122.   initgame();
  2123.   do
  2124.     if(BLACK==thegame.pla)
  2125.       rvalue=mymove();
  2126.     else if(WHITE==thegame.pla)
  2127.       rvalue=enemymove();
  2128.     else 
  2129.       panic("illegal thegame.pla in main() loop");
  2130.   while(rvalue!=BOTHPASS && rvalue!=RESIGN);
  2131. #ifndef    ADDED
  2132.   if(BOTHPASS==rvalue)
  2133. #endif
  2134.     score();
  2135.  
  2136. /*Close the output file.*/
  2137.   if(ofile)
  2138. #ifdef  ADDED
  2139.   {
  2140.     if (outputmode == MGT_OUTPUT)
  2141.       fprintf(ofile, ")\n");
  2142. #endif
  2143.     if(fclose(ofile)) fatal("unable to close output file");
  2144. #ifdef  ADDED
  2145.   }
  2146. #endif
  2147.  
  2148.   exit(0);
  2149. }
  2150.  
  2151. SHAR_EOF
  2152. fi
  2153. exit 0
  2154. #    End of shell archive
  2155.